#include <stdio.h>      /* for printf() and fprintf() */
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h> /* for recv() and send() */
#include <unistd.h>     /* for close() */
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/sendfile.h>
#include <sys/stat.h>

#define RCVBUFSIZE 5024   /* Size of receive buffer */
#define PATH_MAX 1024

#define err_msg printf
#define sys_msg
#define debug_msg printf

static int formatFileName(char *buffer, char *alx_web_dir, char *filename);
static int formatContent(char *tag, char *snd_content, unsigned long int size, int flg, int byt);

static int isdir(const char *path);
static int getContents(char *buffer); // Not working. Under development.

int HandleTCPClient(int clntSocket, char *alx_web_dir)
{
	char echoBuffer[1024], DataTags[1024], content[1024], fileName[PATH_MAX];
	int recvMsgSize, ByteSize;
	off_t offset = 0;
	struct stat stat_buf;
	int fd;
	FILE *fp;

	pid_t Thread;
	
	if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0) sys_msg("recv()");
	echoBuffer[recvMsgSize]='\0';
	if(echoBuffer[0] == 'G' )
	{
		debug_msg("\n****************DEBUG MESSAGE*******************\n");
		debug_msg("REQUEST_FROM_CLIENT>>\n%s", echoBuffer);

//		offset=getContents(echoBuffer);                    // Not working. Under development.
//		printf("\nOFFSET>>>>>>>>>>>>>>>> %d\n", offset);
		
		formatFileName(echoBuffer, alx_web_dir, fileName);
		debug_msg("FULL_FILE_PATH>> %s\n", echoBuffer);
		debug_msg("FILE_NAME>> %s\n", fileName);

		Thread = fork();
		if(Thread == 0)
        	{
			if((fd = open(echoBuffer, O_RDONLY)) == -1)
			{
				debug_msg("Page not found!\n");
				strcpy(DataTags,"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><html><head><title>404 Not found</title></head><body><h1>Page Not Found!</h1><p>The requested URL ");
				strcat(DataTags, fileName);
				strcat(DataTags, " was not found on this server.</p></body></html>");
				formatContent("err.html", content, strlen(DataTags), 0, 0); //Set content to be Not Found!
				debug_msg("RESPONSE_FROM_SERVER>>\n%s", content);
				send(clntSocket, content, strlen(content), 0);
				send(clntSocket, DataTags, strlen(DataTags), 0);
    			}
    			else
			{
				fstat(fd, &stat_buf);
				formatContent(fileName, content, stat_buf.st_size, 1, offset); //Set content to be OK.
				debug_msg("RESPONSE_FROM_SERVER>>\n%s", content);

				send(clntSocket, content, strlen(content), 0);
				
				sendfile(clntSocket, fd, &offset, stat_buf.st_size);
			
				close(fd);
			}
			close(clntSocket);
			debug_msg("***************END DEBUG MESSAGE****************\n");
			exit(0);
		}
		else debug_msg("Process_id:>> %d\n", Thread);
	}
}

static int isdir (const char *path)
{
  struct stat stats;
  return stat (path, &stats) == 0 && S_ISDIR (stats.st_mode);
}

static int formatFileName(char *buffer, char *alx_web_dir, char *filename)
{
	char data[1024], tmp[1024];
	int i;
	sscanf(buffer,"%s %s", data, data);

	if(data[0]!='/') { strcpy(tmp, data); strcpy(data, "/"); strcat(data, tmp); } //add '/' begining of filename if not present
	if(data[strlen(data)-1]=='/') strcat(data,"index.html");	//add default page as "index.html" if the filename ends with '/'
        if (strcmp(data, "/")==0) strcpy(data,"/index.html");	//add default page as "index.html" if the filename only have '/'
	strcpy(tmp, alx_web_dir); strcat(tmp, data);	//Merge Path with filename in tmp.
	if(isdir(tmp)!=0) { strcat(data,"/index.html"); strcat(tmp, "/index.html"); }
	//add default page as "index.html" if the filename is a Directory.

	for(i=0;i<strlen(data);i++) { *filename=data[i]; filename++; } *filename='\0'; //send filename only
	for(i=0;i<strlen(tmp);i++) { *buffer=tmp[i]; buffer++; } *buffer='\0'; //send full path with filename
	return(0);
}

static int getContents(char *buffer) //not working. Under development.
{
	char buf[512], tag[50], data[100], bytes[10];
	int i=0, j=0, k=0, flg=0;
	int byt;

	for(i=0;i<(strlen(buffer)-1);i++)
	{
		buf[j]=buffer[i];
		if(buffer[i]=='\n')
		{
			sscanf(buf, "%s %s", tag, data);
			printf("TAG:> %s %s\n", tag, data);
			if(strcmp(tag, "Range:")==0)
			{
				printf("\n\n\n1.OOOK\n\n");
				for(j=0;j<strlen(data);j++)
				{
					if(data[j]=='-') break;
					if(flg==1) { bytes[k]=data[j]; k++; }
					if(data[j]=='=') flg=1;
				}
			}
			strcpy(buf, "\0"); j=0;
		}
		else j++;
        }
	printf("TOTAL BYTES:> %d\n", atoi(bytes));
	return(atoi(bytes));
}

static int formatContent(char *tag, char *snd_content, unsigned long int size, int flg, int byt)
{
	int i=0, j=0;
	char content[1024], tmp[1024], Week[4], Month[4], Time[9], Day[3], Year[5];
	time_t curtime;
	struct tm *loctime;

	curtime = time (NULL);
	loctime = localtime (&curtime);
	
	sscanf(asctime (loctime), "%s %s %s %s %s", Week, Month, Day, Time, Year);

	for(i=(strlen(tag)-1);i>=0;i--)
	{
		if(tag[i]=='.') { content[j]='\0'; j=0; if(i!=1) break; } content[j]=tag[i]; j++; //Read from back to front until a "." found
		if(i==0) strcpy(content, "*"); //If the "." not found till end, the file name have no extension. So "*"
	}
	strcpy(tmp, content); for(i=(strlen(tmp)-1);i>=0;i--) { content[j]=tmp[i]; j++; }; //Reverse the extension.

	if((strcmp(content,"jpg")==0) || (strcmp(content,"jpeg")==0)) strcpy(content, "image/jpg");
	else if(strcmp(content,"gif")==0) strcpy(content, "image/gif");
	else if(strcmp(content,"png")==0) strcpy(content, "image/png");
	else if(strcmp(content,"bmp")==0) strcpy(content, "image/bmp");
	else if(strcmp(content,"ico")==0) strcpy(content, "image/ico");
	else if(strcmp(content,"tif")==0) strcpy(content, "image/tif");
	else if(strcmp(content,"svg")==0) strcpy(content, "image/svg");
	else if((strcmp(content,"htm")==0) || (strcmp(content,"html")==0)) strcpy(content, "text/html");
	else if(strcmp(content,"swf")==0) strcpy(content, "application/x-shockwave-flash");
	else { strcpy(tmp, content); strcpy(content, "application/"); strcat(content, tmp); }
        strcpy(tmp, content);
	
	switch(flg) {
	case 0: sprintf(content, "HTTP/1.1 404 Not Found\nDate: %s, %s %s %s %s GMT\nServer: Alx Web Server 1.0\nCache-Control: private\nContent-Type: %s\nAccept-Ranges: bytes\nContent-Length: %lu\nConnection: close\n\n\0", Week, Day, Month, Year, Time, tmp, size); break;
	case 1: sprintf(content, "HTTP/1.1 200 OK\nDate: %s, %s %s %s %s GMT\nServer: Alx Web Server 1.0\nCache-Control: private\nContent-Type: %s\nAccept-Ranges: bytes\nContent-Length: %lu\nConnection: close\n\n\0", Week, Day, Month, Year, Time, tmp, size); break;
	}

	for(i=0;i<strlen(content);i++) { *snd_content=content[i]; snd_content++; } *snd_content='\0';
	return(0);
}

